using System;
using System.Drawing;
using System.Windows.Forms;

namespace Scenario_Editor.CustomControls
{
    public partial class ValueBar : UserControl
    {
        #region Private Fields

        private decimal _completeValue;
        private decimal _offset;
        private decimal _value = 0;
        private decimal _valuePerPixel;
        private SolidBrush brush;
        private bool disableLiveValueByMouse = false;
        private Point lastMouselocation = Point.Empty;
        private Pen pen;
        private int StartPointFromValueBar;

        #endregion Private Fields

        #region Public Constructors

        /// <summary>
        /// this is a kind of Trackbar, you can click on the bar to change the value
        /// </summary>
        public ValueBar()
        {
            pen = new Pen(Color.Red);
            brush = new SolidBrush(Color.CornflowerBlue);
            InitializeComponent();
            numericUpDown1.Maximum = 100000;
            numericUpDown1.Minimum = -100000;
            UpdateValues();
        }

        #endregion Public Constructors

        #region Public Events

        /// <summary>
        /// Eventhandler when value is changed
        /// </summary>
        public event EventHandler ValueChanged;

        #endregion Public Events

        #region Public Properties

        /// <summary>
        /// Set or get the Max Value
        /// </summary>
        public int Max
        {
            get
            {
                return (int)this.numericUpDown1.Maximum;
            }
            set
            {
                this.numericUpDown1.Maximum = value;
                UpdateValues();
                panel1.Invalidate();
            }
        }

        /// <summary>
        /// Set or get the min Value
        /// </summary>
        public int Min
        {
            get
            {
                return (int)this.numericUpDown1.Minimum;
            }
            set
            {
                this.numericUpDown1.Minimum = value;
                UpdateValues();
                panel1.Invalidate();
            }
        }

        /// <summary>
        /// Here you can change the Text from the Valuebar
        /// </summary>
        public string Text2
        {
            get { return label1.Text; }
            set { label1.Text = value; }
        }

        /// <summary>
        /// sets or getg the Value
        /// </summary>
        public decimal Value
        {
            get
            {
                return this.numericUpDown1.Value;
            }
            set
            {
                _value = value;
                _value = Math.Max(this.numericUpDown1.Minimum, Math.Min(this.numericUpDown1.Maximum, _value));
                this.numericUpDown1.Value = _value;
                panel1.Invalidate();
            }
        }

        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Sets the max and min  Values
        /// </summary>
        /// <param name="max">sets the max value</param>
        /// <param name="min">sets the min value</param>
        public void SetMaxMin(int max, int min)
        {
            numericUpDown1.Maximum = max;
            numericUpDown1.Minimum = min;

            UpdateValues();
        }

        #endregion Public Methods

        #region Protected Methods

        protected override void OnEnter(EventArgs e)
        {
            base.OnEnter(e);
            this.numericUpDown1.Select(0, this.numericUpDown1.ToString().Length);
        }

        /// <summary>
        /// when value is changed this method is called
        /// </summary>
        /// <param name="e">event Args</param>
        protected virtual void OnValueChanged(EventArgs e)
        {
            if (ValueChanged != null)
                ValueChanged(this, e);
        }

        #endregion Protected Methods

        #region Private Methods

        private void MouseWheelEvent(object sender, MouseEventArgs e)
        {
            if (e.Delta != 0)
            {
                this.disableLiveValueByMouse = true;
                double vector = (e.Delta < 0) ? -1.0 : 1.0;
                this._value += (decimal)((this.Max - this.Min) * 0.001 * vector);
                this.Value = this._value;
            }
        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            if (numericUpDown1.Focused)
            {
                _value = this.numericUpDown1.Value;
            }
            panel1.Invalidate();
        }

        private void panel1_MouseClick(object sender, MouseEventArgs e)
        {
            Point location = this.panel1.PointToClient(MousePosition);
            decimal value = (int)(location.X * _valuePerPixel) + _offset;
            if (value >= this.numericUpDown1.Minimum && value <= this.numericUpDown1.Maximum)
            {
                _value = location.X * _valuePerPixel + _offset;
            }
            OnValueChanged(e);
        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
        }

        private void panel1_MouseEnter(object sender, EventArgs e)
        {
            //if(numericUpDown1.Focused)
            //panel1.Focus();

            // Change value
            this.MouseWheel += new MouseEventHandler(MouseWheelEvent); ;
        }

        private void panel1_MouseLeave(object sender, EventArgs e)
        {
            this.MouseWheel += MouseWheelEvent;
            //this.numericUpDown1.Value = (int)_value;
            this.Value = (int)_value;
            this.disableLiveValueByMouse = false;
            panel1.Invalidate();
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            Point location = this.panel1.PointToClient(MousePosition);
            bool mouseHasMoved = false;
            if (disableLiveValueByMouse)
            {
                if (Math.Abs(location.X - this.lastMouselocation.X) > 5 ||
                  Math.Abs(location.Y - this.lastMouselocation.Y) > 50000000)
                {
                    mouseHasMoved = true;
                    lastMouselocation = location;
                }
            }

            panel1.Focus();

            if (!this.disableLiveValueByMouse || mouseHasMoved)
            {
                lastMouselocation = location;
                if (this.disableLiveValueByMouse)
                {
                    this.disableLiveValueByMouse = false;
                }

                decimal value = (int)(location.X * _valuePerPixel) + _offset;

                if (value >= this.numericUpDown1.Minimum && value <= this.numericUpDown1.Maximum)
                {
                    this.numericUpDown1.Value = value;

                    if (MouseButtons == System.Windows.Forms.MouseButtons.Left)
                        panel1_MouseClick(null, null);
                }
                panel1.Invalidate();
            }
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            int value = 0;
            if (this.disableLiveValueByMouse)
            {
                value = (int)(this._value / (decimal)_valuePerPixel);
                pen.Color = Color.Green;
            }
            else
            {
                value = (int)((numericUpDown1.Value) / (decimal)_valuePerPixel);
                pen.Color = Color.CornflowerBlue;
            }
            if (value > 0)
            {
                g.FillRectangle(pen.Brush, new Rectangle(-this.StartPointFromValueBar, 0, value, panel1.ClientSize.Height));
            }
            else
            {
                g.FillRectangle(pen.Brush, new Rectangle(-this.StartPointFromValueBar + value, 0, -value, panel1.ClientSize.Height));
            }
            pen.Color = Color.DarkBlue;
            g.DrawLine(pen, new Point(-this.StartPointFromValueBar, 0), new Point(-this.StartPointFromValueBar, this.ClientSize.Height));
        }

        private void UpdateValues()
        {
            if (panel1.ClientSize.Width == 0)
                return;
            _completeValue = (numericUpDown1.Maximum - numericUpDown1.Minimum);
            _valuePerPixel = _completeValue / panel1.ClientSize.Width;
            _offset = numericUpDown1.Minimum;
            StartPointFromValueBar = (int)(numericUpDown1.Minimum / (decimal)_valuePerPixel);
        }

        private void ValueBar_Resize(object sender, EventArgs e)
        {
            UpdateValues();
        }

        #endregion Private Methods
    }
}